﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using NetAcademia.Configuration;
using System.Collections.Specialized;
using System.Data;
using System.IO;
using System.Windows.Media;
using System.Windows.Markup;
using System.Windows;
using System.ComponentModel;
using System.Web;
using System.Reflection;
using System.Net;
using System.Data.Common;
using NetAcademia.Web.Mvc;
using System.Data.SqlClient;

namespace NetAcademia.Web.Mvc.ImageRendering
{
	public class XamlToPng
	{

        /// <summary>
        /// This is a backward compatibility branch. It writes directly to the response stream from MS Sql Blob with SequentialAccess.
        /// It uses sqlImage config section, but uses only connectionStringName, command (contentType and bufferSize) setings
        /// </summary>
        /// <param name="key">sqlImage section key</param>
        /// <param name="sqlParameters">url parameters. Those what starts with underline will be used as sql parameter</param>
        /// <param name="httpContext">httpcontext to get the response stream.</param>
        public void WriteImageFromSql(string key, NameValueCollection sqlParameters, HttpContextBase httpContext, string downloadFilename = null)
        {
            SQLImagesSection section = (SQLImagesSection)ConfigurationManager.GetSection("sqlImages");
            if (section == null)
                throw new ConfigurationErrorsException("Missing sqlImages config section");

            var settings = section.BLOBEntries.GetByKey(key);
            if (settings == null)
                throw new ConfigurationErrorsException(string.Format("Missing BLOBEntry config: {0}", key));

            string connectionString = ConfigurationManager.ConnectionStrings[settings.ConnectionStringName].ConnectionString;

            string contentType = settings.ContentType;
            int bufferSize = settings.BufferSize ?? 65536;


            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                using (SqlCommand command = new SqlCommand(settings.Command, connection))
                {
                    command.CommandType = System.Data.CommandType.StoredProcedure;

                    foreach (var k in sqlParameters.AllKeys)
                    {

                        if (k.StartsWith("_"))//sql parameter names prefixed with underscore (because the url can have many other parameters as well)
                        {
                            DbParameter parameter = command.CreateParameter();
                            parameter.ParameterName = k.Substring(1); //removed underscore
                            parameter.Value = sqlParameters[k];
                            command.Parameters.Add(parameter);
                        }
                    }

                    connection.Open();

                    SqlDataReader dr = command.ExecuteReader(CommandBehavior.SequentialAccess);
                    
                    if (dr.Read()) //ha jött vissza rekord
                    {
                        #region oszlopszámok eldöntése és a filename ill. contenttype megszerzése
                        int datColumnNumber = 0; //hányadik oszlopban várjuk az adatot

                        //ha 3 oszlop jött, akkor az első a contenttype, második a filename
                        if (dr.FieldCount > 2)
                        {
                            if (string.IsNullOrWhiteSpace(contentType))
                                contentType = dr.GetString(0);
                            else
                            {
                                var temp = dr.GetString(0); //I do not need it, drop to bin
                            }

                            if (string.IsNullOrWhiteSpace(downloadFilename))
                                downloadFilename = dr.GetString(1);
                            else
                            {
                                var temp = dr.GetString(1); //I do not need it, drop to bin
                            }

                            datColumnNumber = 2;
                            httpContext.Response.ContentType = contentType;
                        }
                        else if (dr.FieldCount > 1) //ha két oszlop jött akkor az első a contenttype
                        {
                            if (string.IsNullOrWhiteSpace(contentType))
                                contentType = dr.GetString(0);
                            else
                            {
                                var temp = dr.GetString(0); //I do not need it, drop to bin
                            }

                            httpContext.Response.ContentType = contentType;
                            datColumnNumber = 1;
                        }
                        #endregion

                        httpContext.Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", downloadFilename));


                        int byteCountRead;
                        int currentIndex;

                        currentIndex = 0;
                        byte[] buffer = new byte[bufferSize];

                        byteCountRead = (int)dr.GetBytes(datColumnNumber, currentIndex, buffer, 0, bufferSize);
                        while (byteCountRead != 0)
                        {
                            if (byteCountRead < bufferSize) //ha kevesebb j0tt vissza, akkor csak annyit szabad visszaadni amennyi jött
                            {
                                byte[] target = new byte[byteCountRead];
                                Array.ConstrainedCopy(buffer, 0, target, 0, byteCountRead);
                                httpContext.Response.BinaryWrite(target);
                            }
                            else
                            {
                                httpContext.Response.BinaryWrite(buffer);
                            }
                            currentIndex += byteCountRead;
                            byteCountRead = (int)dr.GetBytes(datColumnNumber, currentIndex, buffer, 0, bufferSize);
                        }
                        
                    }

                }
            }
        }

        public ContentWithContentType GetPngFromImageXaml(string key, SqlImageRuntimeParameters runtimeParams, NameValueCollection sqlParameters, HttpServerUtilityBase server)
        {

            SQLImagesSection section = (SQLImagesSection)ConfigurationManager.GetSection("sqlImages");
            if (section == null)
                throw new ConfigurationErrorsException("Missing sqlImages config section");

            var settings = section.BLOBEntries.GetByKey(key);
            if (settings == null)
                throw new ConfigurationErrorsException(string.Format("Missing BLOBEntry config: {0}", key));


            Uri baseUri = server.GetBaseUri(settings.ImagesBasePath);


            Dictionary<string, object> data = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

            //copy properties to dictionary
            MergeFromObjectProperties(data, settings, true, baseUri, server);
            //adatbázisból megszerezni, ehhez kell a namedvaluecollection, mert abban lesznek az aláhúzott nevűek a command paraméterek
            MergeDataFromDatabase(data, sqlParameters, settings.ConnectionStringName, settings.Command, baseUri, server);
            //copy explicit parameters to dictionary
            MergeFromObjectProperties(data, runtimeParams, false, baseUri, server);
            //check for prewloadable contents
            DownloadIfNecessary(data, "Image","Watermark");


            System.Diagnostics.Debug.WriteLine(string.Format("GetPngFromImageXaml {0} on thread {1} with {2} data entries", key, System.Threading.Thread.CurrentThread.ManagedThreadId, data.Count));


            ContentWithContentType content;
            if (data.ContainsKey("simple") || !HasExtras(data))
            {
                content = SimpleProcessImageBytes(data, settings.ImageFormat);
            }
            else
            {
                string xaml = GetImageXaml();
                content = STASlave.GeneratePng(xaml, new SqlImagesDataObject(data), settings.ImageFormat);
            }

            if (data.ContainsKey("downloadfilename"))
            {
                string filename = data["downloadfilename"] as string;
                filename = System.IO.Path.ChangeExtension(filename, "png");
                content.DownloadFileName = filename;
            }
            return content;
            
        }


        private ContentWithContentType SimpleProcessImageBytes(Dictionary<string, object> data, GeneratedImageFormat imageFormat)
        {
            ContentWithContentType content = new ContentWithContentType();
            content.ContentType = "image/" + imageFormat.ToString().ToLower();


            double maxWidth = 0;
            double maxHeight = 0;

            if (data.ContainsKey("maxwidth"))
                maxWidth = (double)data["maxwidth"];

            if (data.ContainsKey("maxheight"))
                maxHeight = (double)data["maxheight"];

            if (maxWidth > 0 || maxHeight > 0)
            {
                content.Bits = Helper.ResizePicture((byte[])data["image"], maxWidth, maxHeight, imageFormat.ToString());
            }
            else
            {
                content.Bits = (byte[])data["image"];
            }

            return content;
        }

        /// <summary>
        /// Checks if there is no or max resizing tasks required for this data
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private bool HasExtras(Dictionary<string, object> data)
        {
            if (data.ContainsKey("text") &&  string.IsNullOrWhiteSpace( data["text"] as string)) //has to draw text on it
                return true;

            var affectingProperties = from p in (typeof(BlobEntrySettings)).GetProperties()
                                      let attribs = p.GetCustomAttributes(typeof(BlobEntrySettings.AffectsSimplicityAttribute), false).Cast<BlobEntrySettings.AffectsSimplicityAttribute>()
                             where attribs.Count() > 0
                             select new { p.Name, DiscardableValue = attribs.First().DiscardableValue };

            var affectingDataEntries = from p in affectingProperties
                    join d in data on p.Name.ToLower() equals d.Key.ToLower()
                    select new { d.Value, p.DiscardableValue };


            foreach (var item in affectingDataEntries)
            {
                if (item.DiscardableValue == null || !item.Value.Equals(item.DiscardableValue))
                    return true;
            }
           
            return false;
        }

		public ContentWithContentType GetPngFromTacepaoXaml(string key, TacepaoRuntimeParameters runtimeParams, NameValueCollection sqlParameters, HttpServerUtilityBase server)
		{
			string xaml = GetTacepaoXaml();

			TacepaoSection section = (TacepaoSection)ConfigurationManager.GetSection("tacepao");
			if (section == null)
				throw new ConfigurationErrorsException("Missing tacepao config section");

			TacepaoSettings settings = section.PropertiesList.GetByKey(key);
			if (settings == null)
				throw new ConfigurationErrorsException(string.Format("Missing tacepao config: {0}", key));

            Uri baseUri = server.GetBaseUri(settings.IconBasePath);

			Dictionary<string, object> data = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
			
			//copy properties to dictionary
			MergeFromObjectProperties(data, settings, true, baseUri, server);
			//adatbázisból megszerezni, ehhez kell a namedvaluecollection, mert abban lesznek az aláhúzott nevűek a command paraméterek
            MergeDataFromDatabase(data, sqlParameters, settings.ConnectionStringName, settings.Command, baseUri, server);
			//copy explicit parameters to dictionary
            MergeFromObjectProperties(data, runtimeParams, false, baseUri, server);
            //check for prewloadable contents
            DownloadIfNecessary(data, "Icon");
            
            System.Diagnostics.Debug.WriteLine(string.Format("GetPngFromTacepaoXaml {0} on thread {1} with {2} data entries", key, System.Threading.Thread.CurrentThread.ManagedThreadId, data.Count));

			ContentWithContentType content = STASlave.GeneratePng(xaml, new TacepaoDataObject(data), settings.ImageFormat);
            
            if (data.ContainsKey("downloadfilename"))
            {
                string filename = data["downloadfilename"] as string;
                filename = System.IO.Path.ChangeExtension(filename, settings.ImageFormat.ToString().ToLower());
                content.DownloadFileName = filename;
            }

			return content;
		}

		public ContentWithContentType GetPngFromXaml(string key, NameValueCollection parameters, HttpServerUtilityBase server)
		{
			string xaml;

			XamlToPngSection section = (XamlToPngSection)ConfigurationManager.GetSection("xamlToPng");
			if (section == null)
				throw new ConfigurationErrorsException("Missing xamlToPng config section");

			XamlToPngXamlTemplate settings = section.XamlTemplates.GetByKey(key);
			if (settings == null)
				throw new ConfigurationErrorsException(string.Format("Missing xamlToPng config: {0}", key));

			XamlToPngData dataDefaults = null;
            if (!string.IsNullOrWhiteSpace(settings.Data))
            {
                dataDefaults = section.Data.GetByKey(settings.Data);
                
                if (dataDefaults == null)
                    throw new ConfigurationErrorsException(string.Format("Missing xamlToPng data element with key: {0}", settings.Data), settings.ElementInformation.Source, settings.ElementInformation.LineNumber);
            }

            Uri baseUri = server.GetBaseUri(settings.AssetsBasePath);

			string xamlUrl = settings.Xaml;
            server.TryResolveUrl(ref xamlUrl, baseUri);

			xaml = GetXaml(xamlUrl);
			Dictionary<string, object> data = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

			//először a data szekció beolvasása
			MergeDataFromConfig(data, dataDefaults, settings, baseUri, server);
			//azt felülbírálhatja az ami az adatbázisban van
            MergeDataFromDatabase(data, parameters, settings.ConnectionStringName ?? section.XamlTemplates.DefaultConnectionStringName, settings.Command, baseUri, server);
			//azt meg az ami az url-ben jött
			MergeDataFromParameters(data, parameters, baseUri, server);
            //check for prewloadable contents
            DownloadIfNecessary(data);

            System.Diagnostics.Debug.WriteLine(string.Format("GetPngFromXaml {0} on thread {1} with {2} data entries", key, System.Threading.Thread.CurrentThread.ManagedThreadId, data.Count));
            
            ContentWithContentType content = STASlave.GeneratePng(xaml, new DataObject(data), settings.ImageFormat);

			if (data.ContainsKey("downloadfilename"))
			{
				string filename = data["downloadfilename"] as string;
				filename = System.IO.Path.ChangeExtension(filename, "png");
				content.DownloadFileName = filename;
			}

			return content;
		}

		private void MergeDataFromConfig(Dictionary<string, object> data, XamlToPngData dataDefaults, XamlToPngXamlTemplate settings, Uri baseUri, HttpServerUtilityBase server)
		{
			if (dataDefaults == null)
				return;

			foreach (var item in dataDefaults.Attributes)
			{
                string itemValue = item.Value;
                server.TryResolveUrl(ref itemValue, baseUri);
				data.Add(item.Key, itemValue);
			}
		}

		private void MergeDataFromDatabase(Dictionary<string, object> datas, NameValueCollection parameters, string connectionStringName, string commandText, Uri baseUri, HttpServerUtilityBase server)
		{
			if (string.IsNullOrWhiteSpace(commandText))
				return;

			string connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
			string provider = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;

			var providerFactory = DbProviderFactories.GetFactory(provider);
			

			using (DbConnection connection = providerFactory.CreateConnection())
			{
				connection.ConnectionString = connectionString;

				using (DbCommand command =  connection.CreateCommand())
				{
					command.CommandText = commandText;
					command.CommandType = System.Data.CommandType.StoredProcedure;

					foreach (var key in parameters.AllKeys)
					{

						if (key.StartsWith("_"))//sql parameter names prefixed with underscore (because the url can have many other parameters as well)
						{
							DbParameter parameter = command.CreateParameter();
							parameter.ParameterName = key.Substring(1); //removed underscore
							parameter.Value = parameters[key];
							command.Parameters.Add(parameter);
						}
					}

					connection.Open();

					DbDataReader dr = command.ExecuteReader(); 

					if (dr.Read()) 
					{
						for (int i = 0; i < dr.FieldCount; i++)
						{
							string colName = dr.GetName(i);
							if (!string.IsNullOrWhiteSpace(colName)) //must have a name to place it in a dictionary
							{
								datas.Remove(colName);
								object dbValue = dr.GetValue(i);
                                string strValue = dbValue as string;
                                if (server.TryResolveUrl(ref strValue, baseUri))
                                    dbValue = strValue;
								
								datas.Add(colName, dbValue);
							}
						}

					}
				}
			}

		}

		private void MergeDataFromParameters(Dictionary<string, object> data, NameValueCollection parameters, Uri baseUri, HttpServerUtilityBase server)
		{
			foreach (var key in parameters.AllKeys)
			{
				if (!key.StartsWith("_"))//a tárolteljárás paraméterek kezdődnek aláhúzással, ezeknek nem szabad
				{
					if (data.ContainsKey(key))
						data.Remove(key);

					string itemValue = parameters[key];
                    server.TryResolveUrl(ref itemValue, baseUri);
                    data.Add(key, itemValue);
				}
			}
		}

		private void MergeFromObjectProperties(Dictionary<string, object> data, object Object, bool declaredOnly, Uri baseUri, HttpServerUtilityBase server)
		{
			if (Object != null)
			{
				PropertyInfo[] props;
				Type t = Object.GetType();

				if (declaredOnly)
				{
					props = t.GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public);
				}
				else
				{
					props = t.GetProperties();
				}

				foreach (var prop in props)
				{
					object propValue = prop.GetValue(Object, null);

					if (propValue != null)
					{
						string propString = propValue as string;


                        if (server.TryResolveUrl(ref propString, baseUri))
                        {
                            propValue = propString;
                        }

						data[prop.Name] = propValue;
					}
				}
			}
		}


        /// <summary>
        /// Download data from URLs.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="downloadableKeys">Keys that have urls to download</param>
        /// <remarks>
        /// WPF won't download images if I don't display XAML. So I have to preload resources from the Net.
        /// This method scans the keys in data dictionary for -download postfixes. If it finds any then try to download the resource where that key's value points.
        /// The downloaded bytes go to the dictionary with the url's key without the -download postfix.
        /// It searches not just for -download postfixes but for keys contained in the downloadableKeys parameter. In this case the downloaded bytes overwrite the original url.
        /// </remarks>
        private void DownloadIfNecessary(Dictionary<string, object> data, params string[] downloadableKeys)
        {
            ciComparer ci = new ciComparer();

            var keysToDownload = (from item in data
                                 let isPostfixed = item.Key.EndsWith("-download", StringComparison.InvariantCultureIgnoreCase)
                                 where isPostfixed || downloadableKeys.Contains(item.Key,ci)
                                 select new {Key = item.Key, Value=item.Value, IsPostfixed = isPostfixed}).ToArray();

            foreach (var item in keysToDownload)
            {
                string url = item.Value as string;
                if (!string.IsNullOrWhiteSpace(url))
                {
                    var val = TryToDownload(url);
                    if (val != null)
                    {
                        if (item.IsPostfixed)
                            data[item.Key.Remove(item.Key.Length - 9)] = val;
                        else
                            data[item.Key] = val;
                    }
                }
            }
        }

        private class ciComparer : IEqualityComparer<string>
        {
            public bool Equals(string x, string y)
            {
                return string.Compare(x, y, true) == 0;
            }

            public int GetHashCode(string obj)
            {
                return obj.ToLowerInvariant().GetHashCode();
            }
        }


		/// <summary>
		/// Gets the xaml for Tacepao from resource
		/// </summary>
		/// <returns>XAML in a string</returns>
		private string GetTacepaoXaml()
		{
			string xaml;
			var assembly = Assembly.GetExecutingAssembly();
			using (var buttonxaml = assembly.GetManifestResourceStream("NetAcademia.Web.Mvc.tacepao.xaml"))
			using (StreamReader reader = new StreamReader(buttonxaml))
			{
				xaml = reader.ReadToEnd();
			}
			return xaml;
		}

		/// <summary>
		/// Gets the xaml for SqlImage from resource 
		/// </summary>
		/// <returns>XAML in a string</returns>
		private string GetImageXaml()
		{
			string xaml;
			var assembly = Assembly.GetExecutingAssembly();
			using (var buttonxaml = assembly.GetManifestResourceStream("NetAcademia.Web.Mvc.image.xaml"))
			using (StreamReader reader = new StreamReader(buttonxaml))
			{
				xaml = reader.ReadToEnd();
			}
			return xaml;
		}

		/// <summary>
		/// Returns the given XAML file's content as a string
		/// </summary>
		/// <param name="xamlFilename">Full path to an XAML file</param>
		/// <returns>XAML in  a string</returns>
		private string GetXaml(string xamlFilename)
		{
			string xaml;
			using (StreamReader reader = new StreamReader(xamlFilename))
			{
				xaml = reader.ReadToEnd();
			}
			return xaml;
		}
	
    
        private byte[] TryToDownload(string url)
        {
            byte[] downloadedBytes = null;

            Uri uri = new Uri(url, UriKind.RelativeOrAbsolute);

            if (uri.IsAbsoluteUri && !uri.IsFile)
            {
                WebClient wc = new WebClient();
                downloadedBytes = wc.DownloadData(uri);
            }

            return downloadedBytes;
        }
    }

	/// <summary>
	/// This data class is used by an MVC action to get parameters from the url
	/// then passes it to <see cref="GetPngFromTacepaoXaml"/> method.
	/// </summary>
	public class TacepaoRuntimeParameters
	{
		public string Text { get; set; }
		public double? Rotation { get; set; }
		public double? ContentRotation { get; set; }
		public string Icon { get; set; }
        public string DownloadFileName { get; set; }
	}

	public class SqlImageRuntimeParameters
	{
		public string Text { get; set; }
		public double? Rotation { get; set; }
		public string Image { get; set; }
        public string DownloadFileName { get; set; }
    }

	/// <summary>
	/// Extended dataobject to calculate properties from dictionary members especially for Tacepao
	/// </summary>
	public class TacepaoDataObject:DataObject
	{
		public TacepaoDataObject(Dictionary<string,object> props):base(props)
		{
			//init Icon property and iconPos field value
			GetIcon();
		}

		/// <summary>
		/// The Color of the border around Tacepao.
		/// </summary>
		/// <remarks>
		/// Must be calculated on UI thread from BorderColor.
		/// </remarks>
		public Brush BorderBrush
		{
			get
			{
				Brush brush = null;

				if (properties.ContainsKey("BorderColor"))
				{
					brush = new SolidColorBrush((Color)properties["BorderColor"]);
				}
				return brush;
			}
		}

		/// <summary>
		/// The Color of the text in Tacepao.
		/// </summary>
		/// <remarks>
		/// Must be calculated on UI thread from ForeColor.
		/// </remarks>
		public Brush Foreground
		{
			get
			{
				Brush brush = null;

				if (properties.ContainsKey("ForeColor"))
				{
					brush = new SolidColorBrush((Color)properties["ForeColor"]);
				}
				else
				{
					brush = new SolidColorBrush(Colors.Black);
				}
				return brush;
			}
		}


        public Brush ImageBackground
        {
            get
            {
                Brush brush = null;

                if (properties.ContainsKey("ImageBackgroundColor"))
                {
                    brush = new SolidColorBrush((Color)properties["ImageBackgroundColor"]);
                }
                return brush;
            }
        }

        //object icon;
        ///// <summary>
        ///// Returns either an image url or a byte array with image data.
        ///// </summary>
        //public object Icon
        //{
        //    get
        //    {
        //        return icon;
        //    }
        //}

        private Visibility iconVisibility;
		/// <summary>
		/// Should the icon be displayed or not. It depends on if there is an icon.
		/// </summary>
        public Visibility IconVisibility { get { return iconVisibility; } }

		public string IconMargin
		{
			get
			{
				string margin = null;
				switch (iconPosition)
				{
					case IconPositions.Left:
						margin = "0,0,{0},0";
						break;
					case IconPositions.Top:
						margin = "0,0,0,{0}";
						break;
					case IconPositions.Right:
						margin = "{0},0,0,0";
						break;
					case IconPositions.Bottom:
						margin = "0,{0},0,0";
						break;
					case IconPositions.Background:
						return "0";
					default:
						margin = "0,0,0,{0}";
						break;
				}
				return string.Format(margin, gap);
			}
		}
		public int Row
		{

			get
			{
				int row;
				switch (iconPosition)
				{
					case IconPositions.Left:
						row = 1;
						break;
					case IconPositions.Top:
						row = 0;
						break;
					case IconPositions.Right:
						row = 1;
						break;
					case IconPositions.Bottom:
						row = 2;
						break;
					case IconPositions.Background:
						row = 1;
						break;
					default:
						row = 1;
						break;
				}
				return row;
			}
		}
		public int Column
		{
			get
			{
				int col;
				switch (iconPosition)
				{
					case IconPositions.Left:
						col = 0;
						break;
					case IconPositions.Top:
						col = 1;
						break;
					case IconPositions.Right:
						col = 2;
						break;
					case IconPositions.Bottom:
						col = 1;
						break;
					case IconPositions.Background:
						col = 1;
						break;
					default:
						col = 0;
						break;
				}
				return col;
			}
		}


		private IconPositions iconPosition;
		private double gap;
		/// <summary>
		/// Detect if an url or a byte array is in the daictionary and publishes it as icon.
		/// If the url begins with http (it's a web url) then this method downloads it.
		/// Creates a strongly typed copy of the IconPosition and Gap dictionary values for future calculations
		/// </summary>
		private void GetIcon()
		{
            if (properties.ContainsKey("Icon"))
            {
                iconVisibility = Visibility.Visible;

                if (properties.ContainsKey("IconPosition"))
                {
                    iconPosition = (IconPositions)properties["IconPosition"];
                }

                if (properties.ContainsKey("Gap"))
                {
                    gap = (double)properties["Gap"];
                }
            }
            else
            {
                iconVisibility = Visibility.Collapsed;
            }


		}
	
	}

    public class SqlImagesDataObject : DataObject
    {
        public SqlImagesDataObject(Dictionary<string, object> props)
            : base(props)
        {
            //init Icon property and iconPos field value
            GetImages();
        }

        /// <summary>
        /// The Color of the border around Tacepao.
        /// </summary>
        /// <remarks>
        /// Must be calculated on UI thread from BorderColor.
        /// </remarks>
        public Brush BorderBrush
        {
            get
            {
                Brush brush = null;

                if (properties.ContainsKey("BorderColor"))
                {
                    brush = new SolidColorBrush((Color)properties["BorderColor"]);
                }
                return brush;
            }
        }

        public Brush InnerBorderBrush
        {
            get
            {
                Brush brush = null;

                if (properties.ContainsKey("InnerBorderColor"))
                {
                    brush = new SolidColorBrush((Color)properties["InnerBorderColor"]);
                }
                return brush;
            }
        }

        public Brush ImageBackground
        {
            get
            {
                Brush brush = null;

                if (properties.ContainsKey("ImageBackgroundColor"))
                {
                    brush = new SolidColorBrush((Color)properties["ImageBackgroundColor"]);
                }
                return brush;
            }
        }

        /// <summary>
        /// The Color of the text in Tacepao.
        /// </summary>
        /// <remarks>
        /// Must be calculated on UI thread from ForeColor.
        /// </remarks>
        public Brush Foreground
        {
            get
            {
                Brush brush = null;

                if (properties.ContainsKey("ForeColor"))
                {
                    brush = new SolidColorBrush((Color)properties["ForeColor"]);
                }
                else
                {
                    brush = new SolidColorBrush(Colors.Black);
                }
                return brush;
            }
        }

        private Visibility watermarkVisibility;
        public Visibility WatermarkVisibility { get { return watermarkVisibility; } }

        private Visibility textVisibility;
        public Visibility TextVisibility { get { return textVisibility; } }


        public Stretch Stretch
        {
            get
            {
                System.Windows.Media.Stretch stretch = System.Windows.Media.Stretch.None;

                if (
                    properties.ContainsKey("Width")
                    || properties.ContainsKey("Height")
                    || properties.ContainsKey("MaxWidth")
                    || properties.ContainsKey("MaxHeight")
                    || properties.ContainsKey("ImageWidth")
                    || properties.ContainsKey("ImageHeight"))
                    
                {
                    stretch = System.Windows.Media.Stretch.Uniform;
                }

                return stretch;
            }
        }


        /// <summary>
        /// Detect if an url or a byte array is in the daictionary and publishes it as icon.
        /// If the url begins with http (it's a web url) then this method downloads it.
        /// Creates a strongly typed copy of the IconPosition and Gap dictionary values for future calculations
        /// </summary>
        private void GetImages()
        {

            if (properties.ContainsKey("Text"))
                textVisibility = Visibility.Visible;
            else
                textVisibility = Visibility.Hidden;


            if (properties.ContainsKey("Watermark"))
                watermarkVisibility = Visibility.Visible;
            else
                watermarkVisibility = Visibility.Collapsed;

            
        }

    }

}


